<template>
  <x-layout-main>
    <div class="g-content">
      <el-form ref="formRef" :model="form" :rules="rules" :label-width="90" label-placement="left">
        <template v-if="+route.query.type === 1">
          <el-form-item label="岗位名称" prop="roleName">
            <el-input v-model="form.roleName" maxlength="30" clearable placeholder="请输入岗位名称" show-word-limit />
          </el-form-item>
          <el-form-item label="岗位描述" prop="roleDesc">
            <el-input
              v-model="form.roleDesc"
              type="textarea"
              maxlength="100"
              clearable
              placeholder="请输入岗位描述"
              show-word-limit
            />
          </el-form-item>
        </template>
        <template v-else>
          <el-form-item label="岗位名称" prop="roleName">
            <span>{{ form.roleName }}</span> <n-tag type="primary" style="margin-left: 10px">系统内置</n-tag>
          </el-form-item>
          <el-form-item label="岗位描述" prop="roleDesc">
            {{ form.roleDesc }}
          </el-form-item>
          <el-form-item label="">
            <n-alert type="info" size="small">系统内置岗位仅支持编辑数据权限</n-alert>
          </el-form-item>
        </template>
        <el-form-item label="权限设置" required>
          <el-table
            :key="itemKey"
            ref="table"
            :span-method="tableSpanMethod"
            :data="tableData"
            border
            align="center"
            size="small"
          >
            <el-table-column align="center" prop="index1" label="一级菜单" width="200px">
              <template #default="scope">
                <el-checkbox
                  :key="`${scope.row.index1.checked}${scope.row.index1.indeterminate}`"
                  :indeterminate="scope.row.index1.indeterminate"
                  :checked="scope.row.index1.checked"
                  :label="scope.row.index1.label"
                  :disabled="+route.query.type === 10"
                  @change="checkboxChange($event, scope.row.index1)"
                />
                <br />
              </template>
            </el-table-column>
            <el-table-column align="center" prop="index2" label="二级菜单" width="200px">
              <template #default="scope">
                <el-checkbox
                  v-if="scope.row.index2.isChecked"
                  :key="`${scope.row.index2.checked}${scope.row.index2.indeterminate}`"
                  :indeterminate="scope.row.index2.indeterminate"
                  :checked="scope.row.index2.checked"
                  :label="scope.row.index2.label"
                  :disabled="+route.query.type === 10"
                  @change="checkboxChange($event, scope.row.index2)"
                />
                <br />
              </template>
            </el-table-column>
            <el-table-column align="center" prop="index3" label="三级菜单" width="200px">
              <template #default="scope">
                <el-checkbox
                  v-if="scope.row.index3.isChecked"
                  :key="`${scope.row.index3.checked}${scope.row.index3.indeterminate}`"
                  :indeterminate="scope.row.index3.indeterminate"
                  :checked="scope.row.index3.checked"
                  :label="scope.row.index3.label"
                  :disabled="+route.query.type === 10"
                  @change="checkboxChange($event, scope.row.index3)"
                />
                <br />
              </template>
            </el-table-column>
            <el-table-column prop="children" label="操作">
              <template #default="scope">
                <span v-for="item in scope.row.index3.functionChildren" :key="item.id">
                  <span v-if="item.menuType === 4" style="margin: 7px">
                    <el-checkbox
                      :key="`${item.checked}${item.indeterminate}`"
                      :checked="item.checked"
                      :indeterminate="item.indeterminate"
                      :disabled="+route.query.type === 10"
                      @change="checkboxChange($event, item)"
                    >
                      <span>{{ item.resourceDescription }}</span>
                    </el-checkbox>
                  </span>
                </span>
              </template>
            </el-table-column>
            <el-table-column prop="menu" label="数据权限" width="200px">
              <template #default="scope">
                <el-radio-group v-model="scope.row.index3.dataRange" @change="handleDataRange(scope.row.index3)">
                  <el-radio :value="0">全部</el-radio>
                  <el-radio :value="1">部门</el-radio>
                  <el-radio :value="2">个人</el-radio>
                </el-radio-group>
              </template>
            </el-table-column>
          </el-table>
        </el-form-item>
      </el-form>
      <div style="text-align: right">
        <el-button @click="handleBack">取消</el-button>
        <el-button type="primary" @click="submitRole">确认</el-button>
      </div>
    </div>
  </x-layout-main>
</template>

<script setup lang="ts">
  import { ref, reactive, onMounted, nextTick } from 'vue'
  import XLayoutMain from '@/components/x-layout-main/index.vue'
  import { useMessage, NAlert, NTag } from 'naive-ui'
  import { useStore } from '@/store'
  import { useRoute, useRouter } from 'vue-router'
  const store = useStore()
  const route = useRoute()
  const router = useRouter()
  const message = useMessage()
  const form = ref({
    roleName: null,
    roleDesc: null
  })
  const formRef = ref()
  const table = ref(null)
  const tableData = ref([])
  const treeModelIds = reactive([])
  const treeSelectIds = reactive([])
  const itemKey = Math.random()
  const treeData = ref([])

  const rules = reactive({
    roleName: {
      required: true,
      message: '请输入岗位名称',
      trigger: 'blur'
    },
    roleDesc: {
      required: true,
      message: '请输入岗位名称',
      trigger: 'blur'
    }
  })
  onMounted(() => {
    if (route.query.roleId) {
      getSystemDetail()
    } else {
      getSystemAuthority()
    }
  })
  // 获取资源项详情
  const getSystemDetail = async () => {
    const { data } = await store.dispatch('system/getSystemRleDetail', {
      roleId: route.query.roleId
    })
    form.value.roleName = data.roleName
    form.value.roleDesc = data.roleDesc
    // 格式化数据
    getMenuType(data.resourceList, 4)
    treeData.value = data.resourceList
    await nextTick()
    initData()
  }
  // 获取资源项列表
  const getSystemAuthority = async () => {
    const { data } = await store.dispatch('system/getSystemAuthority', {
      platformType: 2
    })
    // 格式化数据
    getMenuType(data, 4)
    treeData.value = data
    await nextTick()
    initData()
  }
  // 遍历数据获取menuType

  const getMenuType = async (data, targetLevel: number, currentLevel = 1) => {
    data.forEach((item) => {
      item.menuType = currentLevel
      item.dataRange = item.dataRange || 0
      item.checked = item.selected
      if (item.children && item.children.length > 0) {
        getMenuType(item.children, targetLevel, currentLevel + 1)
      }
    })
  }

  const initData = () => {
    treeModelIds.value = []
    treeSelectIds.value = getSelectedIds(treeData.value)
    processingTreeDataA(treeData.value) // 拿到树中的已选中的id和第一层id和倒数第二次id
    processingTreeDataB(treeData.value) // 判断倒数第三层的选中状态，后端返回第三层没有返回选中状态,
    processingTreeData(treeData.value) // 给最后一层加上functionChidren
    treeSelectDefault() // 功能权限树默认选中
    treeToTableData() // 将功能权限树转换成表格形式并合并单元格
  }

  // 遍历所有选中的值
  const getSelectedIds = (arr) => {
    const result = []

    function traverse(obj) {
      if (obj.selected) {
        result.push(obj.id)
      }
      if (obj.children) {
        for (const child of obj.children) {
          traverse(child)
        }
      }
    }

    for (const item of arr) {
      traverse(item)
    }

    return result
  }

  // 更新原数据
  const handleDataRange = (row) => {
    treeData.value.forEach((item) => {
      item?.children.forEach((item1) => {
        item1?.children.forEach((item2) => {
          if (item2.id === row.id) {
            item2.dataRange = row.dataRange
          }
        })
      })
    })
  }

  const processingTreeData = (tree) => {
    // 遍历树  获取id数组
    for (let i = 0; i < tree.length; i++) {
      // 功能层和其他的children区分开来，使用functionChildren来替代children，注意：删除children
      if (tree[i].menuType === 3) {
        tree[i].functionChildren = tree[i].children
        delete tree[i].children
      }
      if (typeof tree[i].children !== 'undefined' && tree[i].children !== null && tree[i].children.length > 0) {
        processingTreeData(tree[i].children)
      }
    }
  }

  const processingTreeDataA = (tree) => {
    // 遍历树  获取id数组
    for (let i = 0; i < tree.length; i++) {
      // 根据需求提交的时候去除第一层和倒数第二层的id
      if (tree[i].menuType === 4 || tree[i].menuType === 1) {
        treeModelIds.value.push(tree[i].id)
      }
      // 树中根据checkFlag来判断当前是否选中
      if (tree[i].checkFlag === true) {
        treeSelectIds.value.push(tree[i].id)
      }
      if (typeof tree[i].children !== 'undefined' && tree[i].children !== null && tree[i].children.length > 0) {
        processingTreeDataA(tree[i].children)
      }
    }
  }

  const processingTreeDataB = (tree) => {
    // 遍历树  获取id数组
    for (let i = 0; i < tree.length; i++) {
      // 判断菜单那一成是否需要选中
      if (tree[i].menuType === 4) {
        // 遍历菜单层，判断菜单层下的所有按钮权限只要有一个选中，根据这一个选中判断菜单层的选中状态
        for (let j = 0; j < tree[i].children?.length; j++) {
          // 如果菜单下的按钮权限有一个包含在treeSelectIds中，则当前菜单被选中
          if (treeSelectIds.value.indexOf(tree[i].children[j].id) !== -1) {
            // 按钮id存在，并且treeSelectIds中没有当前id,则push操作
            if (treeSelectIds.value.indexOf(tree[i].id) === -1) {
              // 则当前菜单被选中后结束当前循环，拿到id,根据id的父节点，子节点判定当前菜单的选中状态
              treeSelectIds.value.push(tree[i].id)
              break
            }
          }
        }
      }
      if (typeof tree[i].children !== 'undefined' && tree[i].children !== null && tree[i].children.length > 0) {
        processingTreeDataB(tree[i].children)
      }
    }
  }

  const handleBack = () => {
    router.back()
  }
  const submitRole = () => {
    formRef.value?.validate(async (valid, fields) => {
      if (valid) {
        // 去除第一层和倒数第二层的id
        // console.log(treeSelectIds.value, 'treeSelectIds')
        // console.log(treeData.value, 'treeData')
        // console.log(findMatchingIds(treeSelectIds.value, treeData.value), 'xxxx')
        let dataRangeList = findMatchingIds(treeSelectIds.value, treeData.value)
        if (dataRangeList.length === 0) {
          return message.warning('请配置权限')
        }
        const params = {
          roleName: form.value.roleName,
          roleDesc: form.value.roleDesc,
          dataRangeList: dataRangeList,
          id: route.query.roleId
        }
        let api = 'getSystemRleSave'
        if (+route.query.type === 1) {
          api = 'getSystemRleSave'
        } else {
          // 内置岗位保存
          api = 'getSystemRleNativeSave'
          dataRangeList = findThreeIds(treeSelectIds.value, treeData.value)
          params.dataRangeList = dataRangeList
          delete params.roleName
          delete params.roleDesc
          delete params.id
        }
        store.dispatch(`system/${api}`, params).then(() => {
          router.back()
        })
      } else {
        console.log(fields)
      }
    })
  }

  // 获取所有选中值以及对应的dataRange
  const findMatchingIds = (ids, nodes) => {
    const results = []

    const traverse = (nodes) => {
      nodes.forEach((node) => {
        if (ids.includes(node.id)) {
          results.push({
            resourceId: node.id,
            dataRange: node.dataRange
          })
        }
        if (node.children && node.children.length > 0) {
          traverse(node.children)
        }
        if (node.functionChildren) {
          traverse(node.functionChildren)
        }
      })
    }

    traverse(nodes)

    return results
  }

  // 获取第三级菜单以及对应的dataRange
  const findThreeIds = (ids, nodes) => {
    const results = []

    const traverse = (nodes) => {
      nodes.forEach((node) => {
        if (ids.includes(node.id)) {
          results.push({
            id: node.roleResourceId,
            dataRange: node.dataRange
          })
        }
        if (node.children && node.children.length > 0) {
          traverse(node.children)
        }
        if (node.functionChildren) {
          traverse(node.functionChildren)
        }
      })
    }

    traverse(nodes)

    return results
  }

  const treeSelectDefault = () => {
    treeSelectIds.value.forEach((item) => {
      const node = searchTree(treeData.value, item)
      fatherSelectedState(node)
      sonSelectedState(node)
    })
  }

  const searchTree = (nodes, searchKey) => {
    for (let i = 0; i < nodes.length; i++) {
      if (nodes[i].id === searchKey) {
        return nodes[i]
      } else {
        if (nodes[i].children && nodes[i].children.length > 0) {
          const res = searchTree(nodes[i].children, searchKey)
          if (res) {
            return res
          }
        } else if (nodes[i].functionChildren && nodes[i].functionChildren.length > 0) {
          const res = searchTree(nodes[i].functionChildren, searchKey)
          if (res) {
            return res
          }
        }
      }
    }
    return null
  }

  const findNodeAndParentsById = (tree, id, parents = []) => {
    for (const node of tree) {
      if (node.id === id) {
        return [...parents, node.id]
      }
      if (node.children) {
        const result = findNodeAndParentsById(node.children, id, [...parents, node.id])
        if (result) {
          return result
        }
      } else if (node.functionChildren) {
        const result = findNodeAndParentsById(node.functionChildren, id, [...parents, node.id])
        if (result) {
          return result
        }
      }
    }
    return null
  }

  const getAllIds = (tree, result) => {
    // 遍历树  获取id数组
    for (let i = 0; i < tree.length; i++) {
      result.push(tree[i].id)
      if (typeof tree[i].children !== 'undefined' && tree[i].children !== null && tree[i].children.length > 0) {
        getAllIds(tree[i].children, result)
      } else if (
        typeof tree[i].functionChildren !== 'undefined' &&
        tree[i].functionChildren !== null &&
        tree[i].functionChildren.length > 0
      ) {
        getAllIds(tree[i].functionChildren, result)
      }
    }
    return result
  }

  const isInclude = (data) => {
    let found = false
    for (let i = 0; i < data.length; i++) {
      if (treeSelectIds.value.indexOf(data[i]) > -1) {
        found = true
        break
      }
    }
    return found
  }

  const isIncludeArr = (data) => {
    // let found = false
    for (let i = 0; i < data.length; i++) {
      if (treeSelectIds.value.indexOf(data[i]) === -1) {
        return false
      }
    }
    return true
  }
  const checkboxChange = async (e, i) => {
    await nextTick()
    if (i.children?.length > 0 || i.functionChildren?.length > 0) {
      // 如果当前节点为父节点
      await nextTick()
      if ((i.checked === false && i.indeterminate === false) || (i.checked === true && i.indeterminate === true)) {
        // 未选中：如果当前父节点未选中，则选中所有子节点
        const cruuentNode = searchTree(treeData.value, i.id)
        const fatherId = findNodeAndParentsById(treeData.value, i.id, [])
        const temIdsArr = getAllIds([cruuentNode], [])
        for (let i = 0; i < fatherId.length; i++) {
          if (!treeSelectIds.value.includes(fatherId[i])) {
            treeSelectIds.value.push(fatherId[i])
            const cruuentNodeB = searchTree(treeData.value, fatherId[i])
            cruuentNodeB.checked = true
          }
        }
        for (let i = 0; i < temIdsArr.length; i++) {
          if (!treeSelectIds.value.includes(temIdsArr[i])) {
            treeSelectIds.value.push(temIdsArr[i])
            const cruuentNodeA = searchTree(treeData.value, temIdsArr[i])
            cruuentNodeA.checked = true
          }
        }
        fatherSelectedState(i)
        sonSelectedState(i)
      } else if (i.checked === true && i.indeterminate === false) {
        // 全选：如果当前是全选状态，点击后子节点全部去除
        const temIdsArr = getAllIds([i], []) // 获取当前节点下的所有节点id
        for (let i = 0; i < temIdsArr.length; i++) {
          treeSelectIds.value.splice(treeSelectIds.value.indexOf(temIdsArr[i]), 1)
        }
        const fatherId = findNodeAndParentsById(treeData.value, i.id, []) // 拿到当前节点的所有父节点的id
        for (let a = fatherId.length - 1; a >= 0; a--) {
          // 从叶子节点开始遍历到最顶层
          const cruuentNode = searchTree(treeData.value, fatherId[a]) // 获取到父节点的内容
          const temIdsArr = getAllIds([cruuentNode], []) // 获取当前父节点下的所有子节点id
          const quchuFistId = temIdsArr.filter((_, index) => index > 0) // 剔除当前父节点自己本身的节点id
          if (!isInclude(quchuFistId) && treeSelectIds.value.includes(fatherId[a])) {
            // 如果当前节点的子节点的所有id不在treeSelectIds中，并且当前父节点所属子节点有任意值存在，则剔除
            treeSelectIds.value.splice(treeSelectIds.value.indexOf(fatherId[a]), 1)
          }
        }
        fatherSelectedState(i)
        sonSelectedState(i)
      }
    } else {
      // 如果当前节点不是父节点
      if (e) {
        // 当前节点选中状态
        findNodeAndParentsById(treeData.value, i.id, []).forEach((element) => {
          const cruuentNode = searchTree(treeData.value, element)
          cruuentNode.checked = true
          if (!treeSelectIds.value.includes(cruuentNode.id)) {
            treeSelectIds.value.push(element)
          }
        })
      } else {
        // 当前节点未选中
        const fatherId = findNodeAndParentsById(treeData.value, i.id, []) // 获取所有父亲节点id
        for (let i = fatherId.length - 1; i >= 0; i--) {
          // 从底层节点开始遍历到顶层节点
          const cruuentNode = searchTree(treeData.value, fatherId[i]) // 根据父节点id找到该节点，拿到遍历的父节点
          const temIdsArr = getAllIds([cruuentNode], []) // 获取当前选中节点父亲节点下面的所有id
          const quchuFistId = temIdsArr.filter((_, index) => index > 0) // 去除当前节点父节点下的所有id，并删除父节点本身id
          if (!isInclude(quchuFistId)) {
            // 判断父节点在treeSelectIds上的选中状态，如果一个都不在treeSelectIds里面，则去除当前节点的id
            treeSelectIds.value.splice(treeSelectIds.value.indexOf(temIdsArr[0]), 1)
          }
        }
      }
    }
    fatherSelectedState(i) // 设置该节点在父节点的选中状态
    sonSelectedState(i) // 设置该节点下所有父节点的所有选中状态
    await nextTick()
    treeToTableData() // 重新编辑table树
  }

  // 设置该节点下所有子节点的所有选中状态
  const sonSelectedState = (i) => {
    getAllIds([i], []).forEach((element) => {
      const cruuentNode = searchTree(treeData.value, element)
      const a = getAllIds([cruuentNode], []).filter((_, index) => index > 0)
      if (isIncludeArr(getAllIds([cruuentNode], [])) && isInclude(getAllIds([cruuentNode], []))) {
        // 全选
        cruuentNode.indeterminate = false
        cruuentNode.checked = true
      } else if (!isIncludeArr(getAllIds([cruuentNode], [])) && isInclude(getAllIds([cruuentNode], []))) {
        // 半选
        cruuentNode.indeterminate = true
        cruuentNode.checked = true
      } else if (!isIncludeArr(getAllIds([cruuentNode], [])) && !isInclude(getAllIds([cruuentNode], []))) {
        // 不选
        cruuentNode.indeterminate = false
        cruuentNode.checked = false
      }
    })
  }

  // 设置该节点在父节点的选中状态
  const fatherSelectedState = (i) => {
    findNodeAndParentsById(treeData.value, i.id, []).forEach((element) => {
      const cruuentNode = searchTree(treeData.value, element)
      const a = getAllIds([cruuentNode], []).filter((_, index) => index > 0)
      if (isIncludeArr(a) && isInclude(a)) {
        // 全选
        cruuentNode.indeterminate = false
        cruuentNode.checked = true
      } else if (!isIncludeArr(a) && isInclude(a)) {
        // 半选
        cruuentNode.indeterminate = true
        cruuentNode.checked = true
      } else if (!isIncludeArr(a) && !isInclude(a)) {
        // 不选
        cruuentNode.indeterminate = false
        cruuentNode.checked = false
      }
    })
  }

  // tree数据处理
  const treeToTableData = () => {
    // 将树状结构格式转换成二维数组表格形式
    const ewArr = parseTreeToRow(treeData.value)
    const tempTableData = []
    ewArr.map((item, index) => {
      if (item.length === 2) {
        item.push({
          label: item[1].label + item.length,
          isChecked: false
        })
      } else if (item.length === 1) {
        item.push({ label: item[0].label + '1', isChecked: false })
        item.push({ label: item[0].label + '2', isChecked: false })
      }
      const obj = {}
      item.map((itemc, indexb) => {
        obj['index' + (indexb + 1)] = {
          id: itemc.id,
          label: itemc.label,
          functionChildren: itemc.functionChildren !== null ? itemc.functionChildren : [],
          children: itemc.children !== null ? itemc.children : [],
          checked: typeof itemc.checked !== 'undefined' ? itemc.checked : false,
          isChecked: itemc.isChecked === false ? itemc.isChecked : true,
          indeterminate: typeof itemc.indeterminate !== 'undefined' ? itemc.indeterminate : false,
          dataRange: itemc.dataRange
        }
        if (itemc.children) {
          obj.children = { data: itemc.children }
        }
      })
      tempTableData.push(obj)
    })
    tableData.value = tempTableData
  }
  // 递归-----将树结构数据格式，转化为，二维数组 表格形式
  const parseTreeToRow = (node, data = [], row = []) => {
    node.forEach((item) => {
      const obj = {
        id: item.id,
        label: item.resourceDescription,
        functionChildren: typeof item.functionChildren !== 'undefined' ? item.functionChildren : null,
        children: item.children !== null ? item.children : null,
        checked: typeof item.checked !== 'undefined' ? item.checked : false,
        indeterminate: typeof item.indeterminate !== 'undefined' ? item.indeterminate : false,
        dataRange: item.dataRange
      }
      if (typeof item.children !== 'undefined') {
        obj.children = item.children.length > 0 ? item.children : []
      }
      if (item.children && item.children.length != 0) {
        parseTreeToRow(item.children, data, [...row, obj])
      } else {
        data.push([...row, obj])
      }
    })
    return data
  }

  // 合并行或列的计算方法
  const tableSpanMethod = ({ row, column, rowIndex, columnIndex }) => {
    return {
      rowspan: columnIndex < 3 ? mergeRows(row[column.property], tableData.value, rowIndex, column.property) : 1,
      colspan: 1
    }
  }

  // 表格单元格合并-----行
  const mergeRows = (value, data, index, property) => {
    // 判断 当前行的该列数据 与 上一行的该列数据 是否相等
    if (index !== 0 && value.label === data[index - 1][property].label) {
      // 返回 0 使表格被跨 行 的那个单元格不会渲染
      return 0
    }
    // 判断 当前行的该列数据 与 下一行的该列数据 是否相等
    let rowSpan = 1
    for (let i = index + 1; i < data.length; i++) {
      if (value.label !== data[i][property].label) {
        break
      }
      rowSpan++
    }
    return rowSpan
  }
</script>
<style scoped lang="scss"></style>
